﻿namespace OpenPms.Services;

public partial class OrderService
{

    public Task<bool> IsCheckin(int hotelId, string idNo) =>
        db.Guests.AnyAsync(ii => ii.HotelId == hotelId && ii.IdNo == idNo);
    /// <summary>
    /// 自动排房
    /// </summary>
    /// <param name="hotelId"></param>
    /// <param name="roomTypeId"></param>
    /// <returns></returns>
    /// <exception cref="ApiException"></exception>
    private async Task<VRoom> TryGetRoomAsync(int hotelId, Guid roomTypeId)
    {
        var v = await db.Rooms.Where(ii => ii.HotelId == hotelId && ii.RoomTypeId == roomTypeId && ii.RoomStatus == ERoomStatus.空).OrderBy(ii => ii.IsDirty).Select(ii => new VRoom() { RoomId = ii.Id, RoomNo = ii.RoomNo, RoomStatus = ii.RoomStatus }).FirstOrDefaultAsync();
        if (v is null)
            throw new ApiException(EResponseCode.无空房);

        if (await db.Rooms.Where(ii => ii.Id == v.RoomId && ii.RoomStatus == ERoomStatus.空).ExecuteUpdateAsync(ii => ii.SetProperty(jj => jj.RoomStatus, ERoomStatus.预)) == 1)
            return v;
        else
            return await TryGetRoomAsync(hotelId, roomTypeId);
    }
    private async Task<VRoom> TryGetRoomAsync(int hotelId, string roomNo)
    {
        var v = await QueryRoomStatusAsync(hotelId, roomNo);
        if (v.RoomStatus != ERoomStatus.空)
            throw new ApiException(EResponseCode.非空房);

        if (await db.Rooms.Where(ii => ii.Id == v.RoomId && ii.RoomStatus == ERoomStatus.空).ExecuteUpdateAsync(ii => ii.SetProperty(jj => jj.RoomStatus, ERoomStatus.预)) == 1)
            return v;
        else
            throw new ApiException(EResponseCode.非空房);
    }

    public async Task<VRoom> ChangeRoomAsync(RequestChangeRoom q)
    {
        var order = await db.Orders.Where(ii => ii.Id == q.OrderId && ii.HotelId == q.HotelId).Select(ii => new { ii.RoomTypeId, ii.RoomNo }).FirstOrDefaultAsync();
        if (order == null)
            throw new ApiException(EResponseCode.订单不存在);
        VRoom vroom = string.IsNullOrEmpty(q.RoomNo) ? await TryGetRoomAsync(q.HotelId, order.RoomTypeId) : await TryGetRoomAsync(q.HotelId, q.RoomNo);


        if (!string.IsNullOrEmpty(order.RoomNo))
            await db.Rooms.Where(ii => ii.HotelId == q.HotelId && ii.RoomNo == order.RoomNo).ExecuteUpdateAsync(ii => ii.SetProperty(jj => jj.RoomStatus, ERoomStatus.空));
        await db.Orders.Where(ii => ii.Id == q.OrderId && ii.HotelId == q.HotelId).ExecuteUpdateAsync(ii => ii.SetProperty(jj => jj.RoomNo, vroom.RoomNo).SetProperty(jj => jj.IsDirty, vroom.IsDirty));
        return vroom;
    }

    public async Task CheckInAsync(int hoteId, RequestCheckIn q)
    {
        if (q.InfoIdCards.Count == 0)
            throw new ApiException(EResponseCode.证件信息不存在);
        var order = await db.Orders.AsTracking().FirstOrDefaultAsync(ii => ii.Id == q.OrderId && ii.HotelId == hoteId);
        if (order == null)
            throw new ApiException(EResponseCode.订单不存在);
        var guests = q.InfoIdCards.Select(ii => new TGuest(ii, q.OrderId, q.DTCheckIn, hoteId));
        db.Guests.AddRange(guests);


        order.DTCheckIn = q.DTCheckIn;
        order.DTCheckOut = q.DTCheckOut;
        order.OrderStatus = EOrderStatus.入住;

        await db.SaveChangesAsync();

        foreach (var idcard in q.InfoIdCards)
            await oss.SaveAsync(idcard.GetId().ToOssFilename(EOssPath.Guest), new InfoIdCardJson(idcard).ToJsonBytes());

        await SendCheckInReservationWXMsgAsync(order);
    }
    public async Task AddMateAsync(int hoteId, RequestAddMate q)
    {
        var guest = new TGuest(q.InfoIdCard, q.OrderId, q.DTCheckIn, hoteId);
        db.Guests.Add(guest);
        await db.SaveChangesAsync();
        await oss.SaveAsync(q.InfoIdCard.GetId().ToOssFilename(EOssPath.Guest), new InfoIdCardJson(q.InfoIdCard).ToJsonBytes());
    }

    public async Task<TReservation> QueryCheckInAsync(int hotelId, string roomNo)
    {
        var resevationId = await db.Orders.Where(ii => ii.HotelId == hotelId && ii.RoomNo == roomNo).Select(ii => ii.ReservationId).FirstOrDefaultAsync();
        if (resevationId == Guid.Empty)
            throw new ApiException(EResponseCode.订单不存在);
        return await db.Reservations.Include(ii => ii.Accounts).Include(ii => ii.Orders).ThenInclude(ii => ii.Guests).FirstAsync();

    }
    public async Task<InfoIdCard?> GetInfoIdCardByGuestIdAsync(Guid guestId)
    {
        var item = await db.Guests.Where(ii => ii.Id == guestId).Select(ii => new { ii.IdNo, ii.IdType }).FirstOrDefaultAsync();
        if (item == null)
            throw new ApiException(EResponseCode.GuestId不存在);
        var bs = await oss.GetAsync(InfoIdCard.GetId(item.IdNo, item.IdType).ToOssFilename(EOssPath.Guest));
        return bs?.To<InfoIdCardJson>().ToInfoIdCard();
    }
    public async Task<InfoIdCard?> GetInfoIdCardByIdNoAsync(string idNo)
    {
        var bs = await oss.GetAsync(InfoIdCard.GetId(idNo, EIdType.身份证).ToOssFilename(EOssPath.Guest));
        return bs?.To<InfoIdCardJson>().ToInfoIdCard();
    }

    public async Task CheckOutAsync(int hotelId, List<Guid> guestIds)
    {
        await db.Database.ExecuteSqlInterpolatedAsync($"PCheckOut {hotelId},{string.Join(",", guestIds)}");
    }
}
